Modification start date
[BattleCats.git] / Assets / Scripts / Imported / Tilemap / Tiles / Rule Tile / Scripts / RuleTile.cs
blob347da600178aa3ce78d737a5540c9b48d8aaccf7
1 using System;
2 using System.Collections.Generic;
3 using UnityEngine.Tilemaps;
5 namespace UnityEngine
7 public class RuleTile<T> : RuleTile
9 public sealed override Type m_NeighborType { get { return typeof(T); } }
11 [Serializable]
12 [CreateAssetMenu]
13 public class RuleTile : TileBase
15 #if UNITY_EDITOR
16 private const string s_XIconString = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAABoSURBVDhPnY3BDcAgDAOZhS14dP1O0x2C/LBEgiNSHvfwyZabmV0jZRUpq2zi6f0DJwdcQOEdwwDLypF0zHLMa9+NQRxkQ+ACOT2STVw/q8eY1346ZlE54sYAhVhSDrjwFymrSFnD2gTZpls2OvFUHAAAAABJRU5ErkJggg==";
17 private const string s_Arrow0 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAACYSURBVDhPzZExDoQwDATzE4oU4QXXcgUFj+YxtETwgpMwXuFcwMFSRMVKKwzZcWzhiMg91jtg34XIntkre5EaT7yjjhI9pOD5Mw5k2X/DdUwFr3cQ7Pu23E/BiwXyWSOxrNqx+ewnsayam5OLBtbOGPUM/r93YZL4/dhpR/amwByGFBz170gNChA6w5bQQMqramBTgJ+Z3A58WuWejPCaHQAAAABJRU5ErkJggg==";
18 private const string s_Arrow1 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAABqSURBVDhPxYzBDYAgEATpxYcd+PVr0fZ2siZrjmMhFz6STIiDs8XMlpEyi5RkO/d66TcgJUB43JfNBqRkSEYDnYjhbKD5GIUkDqRDwoH3+NgTAw+bL/aoOP4DOgH+iwECEt+IlFmkzGHlAYKAWF9R8zUnAAAAAElFTkSuQmCC";
19 private const string s_Arrow2 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAAC0SURBVDhPjVE5EsIwDMxPKFKYF9CagoJH8xhaMskLmEGsjOSRkBzYmU2s9a58TUQUmCH1BWEHweuKP+D8tphrWcAHuIGrjPnPNY8X2+DzEWE+FzrdrkNyg2YGNNfRGlyOaZDJOxBrDhgOowaYW8UW0Vau5ZkFmXbbDr+CzOHKmLinAXMEePyZ9dZkZR+s5QX2O8DY3zZ/sgYcdDqeEVp8516o0QQV1qeMwg6C91toYoLoo+kNt/tpKQEVvFQAAAAASUVORK5CYII=";
20 private const string s_Arrow3 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAAB2SURBVDhPzY1LCoAwEEPnLi48gW5d6p31bH5SMhp0Cq0g+CCLxrzRPqMZ2pRqKG4IqzJc7JepTlbRZXYpWTg4RZE1XAso8VHFKNhQuTjKtZvHUNCEMogO4K3BhvMn9wP4EzoPZ3n0AGTW5fiBVzLAAYTP32C2Ay3agtu9V/9PAAAAAElFTkSuQmCC";
21 private const string s_Arrow5 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAABqSURBVDhPnY3BCYBADASvFx924NevRdvbyoLBmNuDJQMDGjNxAFhK1DyUQ9fvobCdO+j7+sOKj/uSB+xYHZAxl7IR1wNTXJeVcaAVU+614uWfCT9mVUhknMlxDokd15BYsQrJFHeUQ0+MB5ErsPi/6hO1AAAAAElFTkSuQmCC";
22 private const string s_Arrow6 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAACaSURBVDhPxZExEkAwEEVzE4UiTqClUDi0w2hlOIEZsV82xCZmQuPPfFn8t1mirLWf7S5flQOXjd64vCuEKWTKVt+6AayH3tIa7yLg6Qh2FcKFB72jBgJeziA1CMHzeaNHjkfwnAK86f3KUafU2ClHIJSzs/8HHLv09M3SaMCxS7ljw/IYJWzQABOQZ66x4h614ahTCL/WT7BSO51b5Z5hSx88AAAAAElFTkSuQmCC";
23 private const string s_Arrow7 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAABQSURBVDhPYxh8QNle/T8U/4MKEQdAmsz2eICx6W530gygr2aQBmSMphkZYxqErAEXxusKfAYQ7XyyNMIAsgEkaYQBkAFkaYQBsjXSGDAwAAD193z4luKPrAAAAABJRU5ErkJggg==";
24 private const string s_Arrow8 = "iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAYAAAA71pVKAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjAuNWWFMmUAAACYSURBVDhPxZE9DoAwCIW9iUOHegJXHRw8tIdx1egJTMSHAeMPaHSR5KVQ+KCkCRF91mdz4VDEWVzXTBgg5U1N5wahjHzXS3iFFVRxAygNVaZxJ6VHGIl2D6oUXP0ijlJuTp724FnID1Lq7uw2QM5+thoKth0N+GGyA7IA3+yM77Ag1e2zkey5gCdAg/h8csy+/89v7E+YkgUntOWeVt2SfAAAAABJRU5ErkJggg==";
26 private static Texture2D[] s_Arrows;
27 public static Texture2D[] arrows
29 get
31 if (s_Arrows == null)
33 s_Arrows = new Texture2D[10];
34 s_Arrows[0] = Base64ToTexture(s_Arrow0);
35 s_Arrows[1] = Base64ToTexture(s_Arrow1);
36 s_Arrows[2] = Base64ToTexture(s_Arrow2);
37 s_Arrows[3] = Base64ToTexture(s_Arrow3);
38 s_Arrows[5] = Base64ToTexture(s_Arrow5);
39 s_Arrows[6] = Base64ToTexture(s_Arrow6);
40 s_Arrows[7] = Base64ToTexture(s_Arrow7);
41 s_Arrows[8] = Base64ToTexture(s_Arrow8);
42 s_Arrows[9] = Base64ToTexture(s_XIconString);
44 return s_Arrows;
48 public static Texture2D Base64ToTexture(string base64)
50 Texture2D t = new Texture2D(1, 1);
51 t.hideFlags = HideFlags.HideAndDontSave;
52 t.LoadImage(System.Convert.FromBase64String(base64));
53 return t;
56 public virtual void RuleOnGUI(Rect rect, Vector2Int pos, int neighbor)
58 switch (neighbor)
60 case RuleTile.TilingRule.Neighbor.DontCare:
61 break;
62 case RuleTile.TilingRule.Neighbor.This:
63 GUI.DrawTexture(rect, arrows[pos.y * 3 + pos.x]);
64 break;
65 case RuleTile.TilingRule.Neighbor.NotThis:
66 GUI.DrawTexture(rect, arrows[9]);
67 break;
68 default:
69 var style = new GUIStyle();
70 style.alignment = TextAnchor.MiddleCenter;
71 style.fontSize = 10;
72 GUI.Label(rect, neighbor.ToString(), style);
73 break;
75 var allConsts = m_NeighborType.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.FlattenHierarchy);
76 foreach (var c in allConsts)
78 if ((int)c.GetValue(null) == neighbor)
80 GUI.Label(rect, new GUIContent("", c.Name));
81 break;
85 #endif
87 public virtual Type m_NeighborType { get { return typeof(TilingRule.Neighbor); } }
89 private static readonly int[,] RotatedOrMirroredIndexes =
91 {2, 4, 7, 1, 6, 0, 3, 5}, // 90
92 {7, 6, 5, 4, 3, 2, 1, 0}, // 180, XY
93 {5, 3, 0, 6, 1, 7, 4, 2}, // 270
94 {2, 1, 0, 4, 3, 7, 6, 5}, // X
95 {5, 6, 7, 3, 4, 0, 1, 2}, // Y
97 private static readonly int NeighborCount = 8;
99 public Sprite m_DefaultSprite;
100 public Tile.ColliderType m_DefaultColliderType = Tile.ColliderType.Sprite;
101 public TileBase m_Self
103 get { return m_OverrideSelf ? m_OverrideSelf : this; }
104 set { m_OverrideSelf = value; }
107 private TileBase[] m_CachedNeighboringTiles = new TileBase[NeighborCount];
108 private TileBase m_OverrideSelf;
110 [Serializable]
111 public class TilingRule
113 public int[] m_Neighbors;
114 public Sprite[] m_Sprites;
115 public float m_AnimationSpeed;
116 public float m_PerlinScale;
117 public Transform m_RuleTransform;
118 public OutputSprite m_Output;
119 public Tile.ColliderType m_ColliderType;
120 public Transform m_RandomTransform;
122 public TilingRule()
124 m_Output = OutputSprite.Single;
125 m_Neighbors = new int[NeighborCount];
126 m_Sprites = new Sprite[1];
127 m_AnimationSpeed = 1f;
128 m_PerlinScale = 0.5f;
129 m_ColliderType = Tile.ColliderType.Sprite;
131 for (int i = 0; i < m_Neighbors.Length; i++)
132 m_Neighbors[i] = Neighbor.DontCare;
135 public class Neighbor
137 public const int DontCare = 0;
138 public const int This = 1;
139 public const int NotThis = 2;
141 public enum Transform { Fixed, Rotated, MirrorX, MirrorY }
142 public enum OutputSprite { Single, Random, Animation }
145 [HideInInspector] public List<TilingRule> m_TilingRules;
147 public override void GetTileData(Vector3Int position, ITilemap tilemap, ref TileData tileData)
149 TileBase[] neighboringTiles = null;
150 GetMatchingNeighboringTiles(tilemap, position, ref neighboringTiles);
151 var iden = Matrix4x4.identity;
153 tileData.sprite = m_DefaultSprite;
154 tileData.colliderType = m_DefaultColliderType;
155 tileData.flags = TileFlags.LockTransform;
156 tileData.transform = iden;
158 foreach (TilingRule rule in m_TilingRules)
160 Matrix4x4 transform = iden;
161 if (RuleMatches(rule, ref neighboringTiles, ref transform))
163 switch (rule.m_Output)
165 case TilingRule.OutputSprite.Single:
166 case TilingRule.OutputSprite.Animation:
167 tileData.sprite = rule.m_Sprites[0];
168 break;
169 case TilingRule.OutputSprite.Random:
170 int index = Mathf.Clamp(Mathf.FloorToInt(GetPerlinValue(position, rule.m_PerlinScale, 100000f) * rule.m_Sprites.Length), 0, rule.m_Sprites.Length - 1);
171 tileData.sprite = rule.m_Sprites[index];
172 if (rule.m_RandomTransform != TilingRule.Transform.Fixed)
173 transform = ApplyRandomTransform(rule.m_RandomTransform, transform, rule.m_PerlinScale, position);
174 break;
176 tileData.transform = transform;
177 tileData.colliderType = rule.m_ColliderType;
178 break;
183 private static float GetPerlinValue(Vector3Int position, float scale, float offset)
185 return Mathf.PerlinNoise((position.x + offset) * scale, (position.y + offset) * scale);
188 public override bool GetTileAnimationData(Vector3Int position, ITilemap tilemap, ref TileAnimationData tileAnimationData)
190 TileBase[] neighboringTiles = null;
191 var iden = Matrix4x4.identity;
192 foreach (TilingRule rule in m_TilingRules)
194 if (rule.m_Output == TilingRule.OutputSprite.Animation)
196 Matrix4x4 transform = iden;
197 GetMatchingNeighboringTiles(tilemap, position, ref neighboringTiles);
198 if (RuleMatches(rule, ref neighboringTiles, ref transform))
200 tileAnimationData.animatedSprites = rule.m_Sprites;
201 tileAnimationData.animationSpeed = rule.m_AnimationSpeed;
202 return true;
206 return false;
209 public override void RefreshTile(Vector3Int location, ITilemap tileMap)
211 if (m_TilingRules != null && m_TilingRules.Count > 0)
213 for (int y = -1; y <= 1; y++)
215 for (int x = -1; x <= 1; x++)
217 base.RefreshTile(location + new Vector3Int(x, y, 0), tileMap);
221 else
223 base.RefreshTile(location, tileMap);
227 public bool RuleMatches(TilingRule rule, ref TileBase[] neighboringTiles, ref Matrix4x4 transform)
229 // Check rule against rotations of 0, 90, 180, 270
230 for (int angle = 0; angle <= (rule.m_RuleTransform == TilingRule.Transform.Rotated ? 270 : 0); angle += 90)
232 if (RuleMatches(rule, ref neighboringTiles, angle))
234 transform = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -angle), Vector3.one);
235 return true;
239 // Check rule against x-axis mirror
240 if ((rule.m_RuleTransform == TilingRule.Transform.MirrorX) && RuleMatches(rule, ref neighboringTiles, true, false))
242 transform = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(-1f, 1f, 1f));
243 return true;
246 // Check rule against y-axis mirror
247 if ((rule.m_RuleTransform == TilingRule.Transform.MirrorY) && RuleMatches(rule, ref neighboringTiles, false, true))
249 transform = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, -1f, 1f));
250 return true;
253 return false;
256 private static Matrix4x4 ApplyRandomTransform(TilingRule.Transform type, Matrix4x4 original, float perlinScale, Vector3Int position)
258 float perlin = GetPerlinValue(position, perlinScale, 200000f);
259 switch (type)
261 case TilingRule.Transform.MirrorX:
262 return original * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(perlin < 0.5 ? 1f : -1f, 1f, 1f));
263 case TilingRule.Transform.MirrorY:
264 return original * Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(1f, perlin < 0.5 ? 1f : -1f, 1f));
265 case TilingRule.Transform.Rotated:
266 int angle = Mathf.Clamp(Mathf.FloorToInt(perlin * 4), 0, 3) * 90;
267 return Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0f, 0f, -angle), Vector3.one);
269 return original;
272 public virtual bool RuleMatch(int neighbor, TileBase tile)
274 switch (neighbor)
276 case TilingRule.Neighbor.This: return tile == m_Self;
277 case TilingRule.Neighbor.NotThis: return tile != m_Self;
279 return true;
282 public bool RuleMatches(TilingRule rule, ref TileBase[] neighboringTiles, int angle)
284 for (int i = 0; i < NeighborCount; ++i)
286 int index = GetRotatedIndex(i, angle);
287 TileBase tile = neighboringTiles[index];
288 if (!RuleMatch(rule.m_Neighbors[i], tile))
290 return false;
293 return true;
296 public bool RuleMatches(TilingRule rule, ref TileBase[] neighboringTiles, bool mirrorX, bool mirrorY)
298 for (int i = 0; i < NeighborCount; ++i)
300 int index = GetMirroredIndex(i, mirrorX, mirrorY);
301 TileBase tile = neighboringTiles[index];
302 if (!RuleMatch(rule.m_Neighbors[i], tile))
304 return false;
307 return true;
310 private void GetMatchingNeighboringTiles(ITilemap tilemap, Vector3Int position, ref TileBase[] neighboringTiles)
312 if (neighboringTiles != null)
313 return;
315 if (m_CachedNeighboringTiles == null || m_CachedNeighboringTiles.Length < NeighborCount)
316 m_CachedNeighboringTiles = new TileBase[NeighborCount];
318 int index = 0;
319 for (int y = 1; y >= -1; y--)
321 for (int x = -1; x <= 1; x++)
323 if (x != 0 || y != 0)
325 Vector3Int tilePosition = new Vector3Int(position.x + x, position.y + y, position.z);
326 m_CachedNeighboringTiles[index++] = tilemap.GetTile(tilePosition);
330 neighboringTiles = m_CachedNeighboringTiles;
333 private int GetRotatedIndex(int original, int rotation)
335 switch (rotation)
337 case 0:
338 return original;
339 case 90:
340 return RotatedOrMirroredIndexes[0, original];
341 case 180:
342 return RotatedOrMirroredIndexes[1, original];
343 case 270:
344 return RotatedOrMirroredIndexes[2, original];
346 return original;
349 private int GetMirroredIndex(int original, bool mirrorX, bool mirrorY)
351 if (mirrorX && mirrorY)
353 return RotatedOrMirroredIndexes[1, original];
355 if (mirrorX)
357 return RotatedOrMirroredIndexes[3, original];
359 if (mirrorY)
361 return RotatedOrMirroredIndexes[4, original];
363 return original;
366 private int GetIndexOfOffset(Vector3Int offset)
368 int result = offset.x + 1 + (-offset.y + 1) * 3;
369 if (result >= 4)
370 result--;
371 return result;
374 public Vector3Int GetRotatedPos(Vector3Int original, int rotation)
376 switch (rotation)
378 case 0:
379 return original;
380 case 90:
381 return new Vector3Int(-original.y, original.x, original.z);
382 case 180:
383 return new Vector3Int(-original.x, -original.y, original.z);
384 case 270:
385 return new Vector3Int(original.y, -original.x, original.z);
387 return original;
390 public Vector3Int GetMirroredPos(Vector3Int original, bool mirrorX, bool mirrorY)
392 return new Vector3Int(original.x * (mirrorX ? -1 : 1), original.y * (mirrorY ? -1 : 1), original.z);